package org.sardine.beans;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

import org.apache.log4j.Logger;
import org.sardine.beans.support.ElmPropertyDefinition;

/**
 * 每个 bean 实例一个 BeanObjectWrapper 实例，它负责通过反射机制，调用 bean 实例的 setter 方法填充 bean 实例的属性
 * 
 * 
 * @author BearBear
 *
 */
public class BeanObjectWrapperImpl implements BeanObjectWrapper{
	
	private static final Logger log = Logger.getLogger(BeanObjectWrapperImpl.class);
	private final String id;
	private final Object object;
	private BeanObjectIntrospection objectIntrospection = null;

	public BeanObjectWrapperImpl(String id,Object object) {
		this.id = id;
		this.object = object;
	}

	public BeanObjectIntrospection getObjectIntrospection() {
		
		if(this.objectIntrospection == null){
			this.objectIntrospection = new BeanObjectIntrospection(this.object.getClass(),null);
		}
		
		return objectIntrospection;
	}

	/**
	 * 
	 * 调用 bean 实例的 setter 方法填充 bean 实例的属性。
	 * 
	 * @param propertyName bean 实例的属性名
	 * @param propertyValue	试图填入的属性值，类型只能是 String 和集合类型，其他类型无法处理
	 * @return
	 */
	public Object wrapBean(String propertyName,Object propertyValue) {
		
		log.debug("开始填充id为\""+this.id+"\"的实例的"+propertyName+"属性");
		
		if(this.objectIntrospection == null){
			getObjectIntrospection();
		}
		
		BeanObjectPropertyDescriptor bpd = getBeanObjectPropertyDescriptor(propertyName);
		
		if(bpd != null){
			
			Object converted = null;
			Method setterMethod = bpd.getSetterMethod();
			Type[] types = setterMethod.getGenericParameterTypes();
			Type parameterType = types[0];
			
			//对 String 类型进行额外处理，根据 setter 方法的参数类型，将 String 值转换为基本类型、包装类型或数组
			if(propertyValue instanceof String){
				
				converted = StringValueConverter.convert(parameterType,(String)propertyValue);
				
			}else{
				
				converted = propertyValue;
				
			}
			
			try {
				
				setterMethod.invoke(this.object, converted);
				
			} catch (IllegalAccessException e) {
				throw new BeanObjectWrapperException("无法访问"+this.object.getClass().getName()+"的方法"+setterMethod.getName(),e);
			} catch (IllegalArgumentException e) {
				throw new BeanObjectWrapperException("试图调用的"+setterMethod.getName()+"方法的第一个参数类型不是"+parameterType.getTypeName(),e);
			} catch (InvocationTargetException e) {
				throw new BeanObjectWrapperException(setterMethod.getName()+"方法抛出异常:"+e.getCause().getMessage());
			}
			
		}
		
		return getWrappedBean();
		
	}

	public Object getWrappedBean() {
		return this.object;
	}
	
	private BeanObjectPropertyDescriptor getBeanObjectPropertyDescriptor(String fieldName){
		return this.objectIntrospection.getPropertyDescriptors().get(fieldName);
	}
	
	

}
